package org.balabala.gateway.controller;


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import feign.FeignException;
import io.lettuce.core.RedisCommandExecutionException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.balabala.gateway.entity.Comment;
import org.balabala.gateway.entity.Video;
import org.balabala.gateway.feign.VideoFeign;
import org.balabala.gateway.redis.UserManager;
import org.balabala.gateway.redis.VideoManager;
import org.balabala.gateway.response.Resp;
import org.balabala.gateway.response.UnifiedResponse;
import org.balabala.gateway.response.ResponseInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.*;

@RestController
@Slf4j
@RequestMapping("/api/video")
public class VideoRouter {
    @Autowired
    private VideoManager videoManager;

    @Resource
    private VideoFeign videoFeign;

    /**
     * 获取视频信息
     *
     * @param videoId
     * @return
     */
    @RequestMapping("/info")
    public UnifiedResponse getVideo(Long videoId) {
        UnifiedResponse response = new UnifiedResponse();
        if (videoId == null) {
            log.error("getVideo parameter videoId is null");
            response.setCode(ResponseInfo.OPERATE_FAILED);
            response.setErrorMessage(ResponseInfo.PARAMETER_ERROR);
            return response;
        }

        Video video = videoManager.getVideo(videoId);
        if (video == null) {
            Resp resp = null;
            try {
                resp = videoFeign.getVideoInfo(videoId);
                if (resp.getCode() == 0) {
                    video = resp.getData(new TypeReference<Video>() {
                    });
                    if (video != null) {
                        videoManager.setVideo(video);
                    } else {
                        response.setCode(ResponseInfo.OPERATE_FAILED);
                        response.setErrorMessage(ResponseInfo.VIDEO_NOTFOUND);
                        return response;
                    }
                } else {
                    response.setCode(ResponseInfo.OPERATE_FAILED);
                    response.setErrorMessage((String) resp.get("msg"));
                    return response;
                }
            } catch (FeignException exception) {
                log.error("videoFeign.getVideoInfo request error : " + exception);
                response.setCode(ResponseInfo.SERVER_FAILED);
                response.setErrorMessage(ResponseInfo.RPC_ERROR);
                return response;
            }
        } else {
            log.info("getVideo from redis,videoId : " + videoId);
        }
        response.setCode(ResponseInfo.SUCCEED);
        response.setData(new Video[]{video});
        return response;
    }


    /**
     * 獲取視頻URL
     *
     * @param videoId
     * @return
     */
    @GetMapping("/get_url")
    public UnifiedResponse getVideoURL(Long videoId) {
        UnifiedResponse response = new UnifiedResponse();
        if (videoId == null) {
            log.error("getVideoURL parameter videoId is null");
            response.setCode(ResponseInfo.OPERATE_FAILED);
            response.setErrorMessage(ResponseInfo.PARAMETER_ERROR);
            return response;
        }

        log.info("getVideoURL parameter videoId : " + videoId);

        try {
            Resp resp = videoFeign.getVideoURL(videoId);
            if (resp.getCode() == 0) {
                response.setCode(ResponseInfo.SUCCEED);
                response.setData(new String[]{(String) resp.get("url")});
            } else {
                response.setCode(ResponseInfo.OPERATE_FAILED);
                response.setErrorMessage(ResponseInfo.VIDEO_URL_NOTFOUND);
            }
        } catch (FeignException e) {
            response.setCode(ResponseInfo.SERVER_FAILED);
            log.error("videoFeign.getVideoURL request error : " + e);
        }
        return response;
    }


    /**
     * 上传视频
     *
     * @param request
     * @param video
     * @return
     * @throws IOException
     */
    @PostMapping("/upload")
    public UnifiedResponse uploadVideo(HttpServletRequest request, Video video) {
        UnifiedResponse response = new UnifiedResponse();
        if (video == null || video.getUid() == null) {
            log.error("uploadVideo video is null");
            response.setCode(ResponseInfo.OPERATE_FAILED);
            response.setErrorMessage(ResponseInfo.PARAMETER_ERROR);
            return response;
        }

        log.info("uploadVideo parameter video : " + video);
        boolean isMultipart = ServletFileUpload.isMultipartContent(request);
        if (!isMultipart) {
            log.error("uploadVideo video is not multipart");
            response.setCode(ResponseInfo.SERVER_FAILED);
            response.setErrorMessage(ResponseInfo.PARAMETER_ERROR);
            return response;
        }

        MultipartHttpServletRequest req = (MultipartHttpServletRequest) request;
        MultipartFile file = req.getFile("file");
        String contentType = file.getContentType();
        String s = JSON.toJSONString(video);
        try {
            Resp resp = videoFeign.upload(file, s);
            if (resp.getCode() == 0) {
                response.setCode(ResponseInfo.SUCCEED);
                video = resp.getData(new TypeReference<Video>() {
                });
                videoManager.setVideo(video);
                resp.setData(new Video[]{video});
            } else {
                response.setCode(ResponseInfo.OPERATE_FAILED);
                response.setErrorMessage((String) resp.get("msg"));
            }
        } catch (Exception e) {
            log.error("videoFeign.upload error or redis error : " + e);
            response.setCode(ResponseInfo.SERVER_FAILED);
        }

        return response;
    }


    /**
     * 获取高热视频
     *
     * @param num
     * @return
     */
    @GetMapping("/hot_videos")
    public UnifiedResponse getHotVideos(Integer num) {
        UnifiedResponse response = new UnifiedResponse();
        if (num == null) {
            num = 10;
        }
        log.info("getHotVideos num : " + num);

        List hotVideoList = videoManager.getHotVideos(num);
        if (hotVideoList.size() == 0) {
            try {
                Resp resp = videoFeign.getHotVideos(num);
                if (resp.getCode() == 0) {
                    response.setCode(ResponseInfo.SUCCEED);
                    Video hotVideos[] = resp.getData(new TypeReference<Video[]>() {
                    });
                    try {
                        videoManager.setHotVideos(hotVideos);
                    } catch (RedisCommandExecutionException e) {
                        log.error("redis setHotVideos error : " + e);
                    }
                    response.setData(hotVideos);
                } else {
                    response.setCode(ResponseInfo.OPERATE_FAILED);
                    response.setErrorMessage((String) resp.get("msg"));
                }
            } catch (FeignException e) {
                log.error("videoFeign.getHotVideos request error : " + e);
            }
        } else {
            log.info("get hotVideos from redis");
            response.setCode(ResponseInfo.SUCCEED);
            response.setData(hotVideoList.toArray());
        }

        return response;
    }


    /**
     * 下架视频
     * @param videoIds
     * @return
     */
    @PostMapping("/down_video")
    public UnifiedResponse offShelves(@RequestBody Long[] videoIds) {
        UnifiedResponse response = new UnifiedResponse();
        if (videoIds == null || videoIds.length == 0) {
            log.error("getVideoURL parameter videoIds is null");
            response.setCode(ResponseInfo.OPERATE_FAILED);
            response.setErrorMessage(ResponseInfo.PARAMETER_ERROR);
            return response;
        }

        log.info("getVideoURL parameter videoId : " + videoIds.toString());

        try{
            Resp resp = videoFeign.offShelfVideo(videoIds);
            if (resp.getCode() == 0) {
                response.setCode(ResponseInfo.SUCCEED);
            } else {
                response.setCode(ResponseInfo.OPERATE_FAILED);
            }
        }catch (FeignException e){
            response.setCode(ResponseInfo.SERVER_FAILED);
            log.error("videoFeign.offShelfVideo request error : " + e);
        }

        return response;
    }


    /**
     * 增加视频播放次数
     *
     * @param videoId
     * @return
     */
    @PostMapping("/add_playnum")
    public UnifiedResponse addPlayNum(Long videoId) {
        UnifiedResponse response = new UnifiedResponse();
        if (videoId == null) {
            log.error("addPlayNum videoId is null");
            response.setCode(ResponseInfo.OPERATE_FAILED);
            response.setErrorMessage(ResponseInfo.PARAMETER_ERROR);
            return response;
        }

        try {
            Video video = videoManager.getVideo(videoId);
            if (video == null) {
                Resp resp = videoFeign.getVideoInfo(videoId);
                video = resp.getData(new TypeReference<Video>() {
                });
                if (video == null) {
                    response.setCode(ResponseInfo.OPERATE_FAILED);
                    response.setErrorMessage(ResponseInfo.VIDEO_NOTFOUND);
                    return response;
                } else {
                    videoManager.setVideo(video);
                }
            } else {
                video.setPlayNum(video.getPlayNum() + 1);
            }
        } catch (Exception e) {
            log.error("videoManager.getVideo error or videoFeign.getVideoInfo error : " + e);
        }

        response.setCode(ResponseInfo.SUCCEED);
        return response;
    }


    /**
     * 获取视频的评论
     *
     * @param videoId
     * @param limit
     * @param offset
     * @return
     */
    @GetMapping("/video_comments")
    public UnifiedResponse getVideoComments(Long videoId, Integer limit, Integer offset) {
        UnifiedResponse response = new UnifiedResponse();
        if (videoId == null) {
            log.error("getVideoComments parameter videoId is null");
            response.setCode(ResponseInfo.OPERATE_FAILED);
            response.setErrorMessage(ResponseInfo.PARAMETER_ERROR);
            return response;
        }

        if (limit == null || offset == null) {
            limit = 20;
            offset = 0;
        }

        log.info("getVideoComments parameter videoId limit offset : " + videoId + " " + limit + " " + offset);


        try {
            Resp resp = videoFeign.getVideoComments(videoId, limit, offset);
            if (resp.getCode() == 0) {
                response.setCode(ResponseInfo.SUCCEED);
                List<Comment> commentList = resp.getData(new TypeReference<List<Comment>>() {
                });
                response.setData(commentList.toArray());
            } else {
                response.setCode(ResponseInfo.OPERATE_FAILED);
                response.setErrorMessage((String) resp.get("msg"));
            }
        } catch (FeignException e) {
            log.error("videoFeign.getVideoComments request error:" + e);
        }

        return response;
    }

    /**
     * 获取用户发布的视频
     *
     * @param uid
     * @param page
     * @param limit
     * @return
     */
    @GetMapping("/get_videos")
    public UnifiedResponse getUserVideos(Long uid, Integer page, Integer limit) {
        UnifiedResponse response = new UnifiedResponse();
        if (uid == null) {
            log.error("getUserVideos parameter uid is null");
            response.setCode(ResponseInfo.OPERATE_FAILED);
            response.setErrorMessage(ResponseInfo.PARAMETER_ERROR);
            return response;
        }

        if (page == null || limit == null) {
            page = 1;
            limit = 20;
        }

        log.info("getUserVideos parameter page: " + page + " limit: " + limit + " uid:" + uid);


        try {
            Resp resp = videoFeign.getUserVideos(uid, page, limit);
            if (resp.getCode() == 0) {
                response.setCode(ResponseInfo.SUCCEED);
            } else {
                response.setCode(ResponseInfo.OPERATE_FAILED);
                response.setErrorMessage((String) resp.get("msg"));
            }
        } catch (FeignException e) {
            log.error("userFeign.getUserFavourite request error : " + e);
            response.setCode(ResponseInfo.SERVER_FAILED);
            response.setErrorMessage(ResponseInfo.RPC_ERROR);
        }

        return response;
    }


    /**
     * 获取视频缩略图url
     * @param videoId
     * @return
     */
    @GetMapping("/get_frame_url")
    public UnifiedResponse getFrameUrl(@RequestParam Long videoId){

        UnifiedResponse response = new UnifiedResponse();
        if (videoId == null){
            log.error("getFrameUrl parameter videoId is null");
        }

        log.info("getFrameUrl parameter videoId : " + videoId);


        try {
            Resp resp = videoFeign.getFrameUrl(videoId);
            if (resp.getCode() == 0) {
                response.setCode(ResponseInfo.SUCCEED);
                response.setData(new String[]{(String) resp.get("url")});
            } else {
                response.setCode(ResponseInfo.OPERATE_FAILED);
                response.setErrorMessage((String) resp.get("msg"));
            }
        } catch (FeignException e) {
            log.error("videoFeign.getFrameUrl request error : " + e);
            response.setCode(ResponseInfo.SERVER_FAILED);
            response.setErrorMessage(ResponseInfo.RPC_ERROR);
        }

        return response;

    }

}
